package cn.xshi.iot.live.service.impl;

import cn.xshi.common.base.BaseResult;
import cn.xshi.common.util.StringUtil;
import cn.xshi.iot.live.timer.AutoKillTask;
import cn.xshi.iot.live.timer.AutoKillTranscribeTask;
import cn.xshi.iot.live.util.*;
import cn.xshi.iot.live.worker.FlexPusher;
import cn.xshi.iot.live.worker.TranscribePusher;
import cn.xshi.iot.live.service.LiveService;
import cn.xshi.iot.live.model.CameraEntity;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
 * @Desc 视频直播流
 * @Author 邓纯杰
 * @CreateTime 2012-12-12 12:12:12
 */
@Service
@Slf4j
@Data
public class LiveServiceImpl implements LiveService {

    @Resource
    AutoKillTask autoKillTask;//直播，回放终止器

    @Resource
    AutoKillTranscribeTask autoKillTranscribeTask;//录制视频终止器

    @Resource
    ScreenShotUtil screenShotUtil;//截图工具类

    @Resource
    ActualTimeUtil actualTimeUtil;

    @Resource
    PlaybackUtil playbackUtil;

    /**
     * 实时预览
     * @param cameraEntity
     * @return
     */
    public BaseResult live(CameraEntity cameraEntity){
        BaseResult result = new BaseResult();
        result.setMessage("播放成功！");
        if (!StringUtils.isEmpty(cameraEntity.getIp()) && !StringUtils.isEmpty(cameraEntity.getUsername()) && !StringUtils.isEmpty(cameraEntity.getPassword()) && !StringUtils.isEmpty(cameraEntity.getChannel())) {
            CameraEntity cameraEntityCache = CacheUtil.STREAMMAP.get(cameraEntity.getStream());
            if(null == cameraEntityCache){//首次推流
                // 开始推流
                cameraEntity = openStream(cameraEntity);
                result.setData(cameraEntity.getUrl());
                log.info("打开：" + cameraEntity.getRtsp());
                result.setData(cameraEntity);
                return result;
            }
            if(null == cameraEntity.getStartTime()){ //直播流
                cameraEntity = cameraEntityCache;
                log.info("通过已播放通道中直接打开：" + cameraEntity.getRtsp()+",当前错误信息："+cameraEntity.getErrorCount());
            }else{//回放流
                if(cameraEntity.getReStart()){//如果执行重播则删除缓存中历史并终止其线程（支持每一个客户端重置并且不影响其它客户端播放）
                    autoKillTask.killTask(cameraEntity.getStream());
                    try {
                        while (true){
                            if(null == CacheUtil.STREAMMAP.get(cameraEntity.getStream())){
                                cameraEntity = openStream(cameraEntity);//重新执行新的线程
                                log.info(cameraEntity.getRtsp() + " 重新开启回放...");
                                break;
                            }
                            Thread.sleep(500);
                        }
                    }catch (Exception e){

                    }
                }else{
                    cameraEntity = cameraEntityCache;
                    log.info(cameraEntity.getRtsp() + " 开启回放...");
                }
            }
            result.setData(cameraEntity);
        }else{
            result.setMessage("播放失败，未能获取到摄像头参数！");
            result.setStatus(500);
        }
        return result;
    }


    /**
     * 推流器
     * @param cameraEntity
     * @return
     */
    private CameraEntity openStream(CameraEntity cameraEntity) {
        // 生成token
        String token = cameraEntity.getStream();
        cameraEntity.setToken(token);
        if (null != cameraEntity.getStartTime()) {
            //回放（此时的用户名和IP及端口都是NVR存储设备）
            playbackUtil.doPlayback(cameraEntity);
        } else {
            // 直播流
            actualTimeUtil.doActualTime(cameraEntity);
        }
        cameraEntity.setCount(cameraEntity.getCount() == null ?1:cameraEntity.getCount());
        FlexPusher.MyRunnable job = new FlexPusher.MyRunnable(cameraEntity);// 执行任务
        if(null ==  CacheUtil.jobMap.get(token)){//线程不存在放入（一个客户端设备只保证一个活的线程）
            FlexPusher.MyRunnable.es.execute(job);
            CacheUtil.jobMap.put(token, job);
        }
        return cameraEntity;
    }

    /**
     * 关闭实时预览（暂时不生效）
     * @param cameraEntity
     * @return
     */
    public BaseResult stopLive(CameraEntity cameraEntity){
        BaseResult result = new BaseResult();
        if (!StringUtils.isEmpty(cameraEntity.getStream())) {
            if (CacheUtil.jobMap.containsKey(cameraEntity.getStream()) && CacheUtil.STREAMMAP.containsKey(cameraEntity.getStream())) {
                if (0 < CacheUtil.STREAMMAP.get(cameraEntity.getStream()).getCount()) {
                    // 人数-1
                    CacheUtil.STREAMMAP.get(cameraEntity.getStream()).setCount(CacheUtil.STREAMMAP.get(cameraEntity.getStream()).getCount() - 1);
                    log.info("关闭：" + CacheUtil.STREAMMAP.get(cameraEntity.getStream()).getRtsp() + ";当前使用人数为：" + CacheUtil.STREAMMAP.get(cameraEntity.getStream()).getCount());
                }
            }
        }
        return result;
    }


    /**
     * 录制视频
     * @param cameraEntity
     * @return
     */
    public BaseResult startTranscribe(CameraEntity cameraEntity){
        String token = cameraEntity.getStream();
        cameraEntity.setToken(token);
        BaseResult baseResult = new BaseResult();
        if(StringUtil.isEmpty(cameraEntity.getStream())){
            baseResult.setMessage("未能获取到设备编号！");
            return baseResult;
        }
        if(StringUtil.isEmpty(cameraEntity.getVideoName())){
            baseResult.setMessage("未能获取到录制输出视频名称！");
            return baseResult;
        }
        if(StringUtil.isEmpty(cameraEntity.getVideoType())){
            baseResult.setMessage("未能获取到录制输出视频类型！");
            return baseResult;
        }
        actualTimeUtil.doActualTime(cameraEntity);
        String inputFile = cameraEntity.getRtsp(); //-该地址可以是网络直播/录播地址，也可以是远程/本地文件路径
        String outputFile = cameraEntity.getPath()+"/"+cameraEntity.getVideoName()+"."+cameraEntity.getVideoType();// -该地址只能是文件地址，如果使用该方法推送流媒体服务器会报错，原因是没有设置编码格式
        Integer audioChannel = cameraEntity.getAudio();//是否录制音频0:不录制/1:录制
        if(StringUtil.isEmpty(inputFile)){
            log.info("未能获取到视频源地址！");
            return null;
        }
        if(StringUtil.isEmpty(outputFile)){
            log.info("未能获取到录制输出地址！");
            return null;
        }
        if(null == audioChannel){
            log.info("未能获取到录制音频参数！");
            return null;
        }
        TranscribePusher.TranscribePusherRunnable job = new TranscribePusher.TranscribePusherRunnable(cameraEntity);// 执行任务
        if(null ==  CacheUtil.transcribeJobMap.get(cameraEntity.getStream())){//线程不存在放入（一个客户端设备只保证一个活的线程）
            TranscribePusher.TranscribePusherRunnable.es.execute(job);
            cameraEntity.setCount(cameraEntity.getCount()+1);
            CacheUtil.transcribeJobMap.put(cameraEntity.getStream(), job);
        }
        return baseResult;
    }

    /**
     * 停止录制
     * @param cameraEntity
     * @return
     */
    public BaseResult stopTranscribe(CameraEntity cameraEntity){
        BaseResult baseResult = new BaseResult();
        if(StringUtil.isEmpty(cameraEntity.getStream())){
            baseResult.setMessage("未能获取到设备编号！");
            return baseResult;
        }
        autoKillTranscribeTask.killTask(cameraEntity.getStream());
        try {
            while (true){
                if(null == CacheUtil.transcribeMap.get(cameraEntity.getStream())){
                    cameraEntity = openStream(cameraEntity);//重新执行新的线程
                    baseResult.setMessage(cameraEntity.getStream() + " 停止录制成功");
                    log.info(cameraEntity.getStream() + " 停止录制成功...");
                    break;
                }
                Thread.sleep(500);
            }
        }catch (Exception e){
            baseResult.setMessage(cameraEntity.getStream() + " 停止录制失败");
            log.info(cameraEntity.getStream() + " 停止录制失败...");
        }
        return baseResult;
    }

    /**
     * 截图
     * @param cameraEntity
     * @return
     */
    public BaseResult screenShot(CameraEntity cameraEntity){
        BaseResult baseResult = new BaseResult();
        actualTimeUtil.doActualTime(cameraEntity);
        boolean result = screenShotUtil.fetchFrame(cameraEntity);
        if(result){
            baseResult.setMessage("截图成功！");
        }else{
            baseResult.setMessage("截图失败");
        }
        return baseResult;
    }
}
